package org.zoomdev.zoom.common.utils;


import java.util.Arrays;

public final class HexUtils {
    private final static char[] HEX = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E',
            'F'};
    /**
     * 用于建立十六进制字符的输出的小写字符数组
     */
    private static final char[] DIGITS_LOWER = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd',
            'e', 'f'};
    /**
     * 用于建立十六进制字符的输出的大写字符数组
     */
    private static final char[] DIGITS_UPPER = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D',
            'E', 'F'};

    public static String toHex(byte[] b) {
        StringBuilder sb = new StringBuilder();
        for (byte c : b) {
            sb.append(Integer.toBinaryString(c));
        }

        return sb.toString();
    }

    public static String toHexString(byte[] d, int s, int n) {
        final char[] ret = new char[n * 2];
        final int e = s + n;

        int x = 0;
        for (int i = s; i < e; ++i) {
            final byte v = d[i];
            ret[x++] = HEX[0x0F & (v >> 4)];
            ret[x++] = HEX[0x0F & v];
        }
        return new String(ret);
    }

    /**
     * @param data
     * @param start
     * @return
     */
    public static short toShort(byte[] data, int start) {
        return (short) (((data[start + 1] << 8) & 0xff00) | (data[start] & 0xff));
    }

    public static int toInt(byte[] data, int start) {
        return ((data[start + 3] << 24) & 0xff000000) | ((data[start + 2] << 16) & 0xff0000)
                | ((data[start + 1] << 8) & 0xff00) | (data[start] & 0xff);
    }

    public static byte[] copy(byte[] bytes, int dataStart, short len) {
        return Arrays.copyOfRange(bytes, dataStart, len);
    }

    /**
     * 将字节数组转换为十六进制字符数组
     *
     * @param data byte[]
     * @return 十六进制char[]
     */
    public static char[] encodeHex(byte[] data) {
        return encodeHex(data, true);
    }

    /**
     * 将字节数组转换为十六进制字符数组
     *
     * @param data        byte[]
     * @param toLowerCase <code>true</code> 传换成小写格式 ， <code>false</code> 传换成大写格式
     * @return 十六进制char[]
     */
    public static char[] encodeHex(byte[] data, boolean toLowerCase) {
        return encodeHex(data, data.length, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER);
    }

    /**
     * 将字节数组转换为十六进制字符串
     *
     * @param data byte[]
     * @return 十六进制String
     */
    public static String encodeHexStr(byte[] data) {
        return encodeHexStr(data, false);
    }

    public static String encodeHexStr(byte[] data, int start, int len) {
        return new String(encodeHex(data, start, len, DIGITS_LOWER));
    }

    public static String encodeHexStr(byte[] data, int len) {
        return encodeHexStr(data, len, false);
    }

    /**
     * 将字节数组转换为十六进制字符串
     *
     * @param data        byte[]
     * @param toLowerCase <code>true</code> 传换成小写格式 ， <code>false</code> 传换成大写格式
     * @return 十六进制String
     */
    public static String encodeHexStr(byte[] data, boolean toLowerCase) {
        return encodeHexStr(data, data.length, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER);
    }

    public static String encodeHexStr(byte[] data, int len, boolean toLowerCase) {
        return encodeHexStr(data, len, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER);
    }

    public static byte[] decodeHex(String data) {
        return decodeHex(data.toCharArray());
    }

    /**
     * 将十六进制字符数组转换为字节数组
     *
     * @param data 十六进制char[]
     * @return byte[]
     * @throws RuntimeException 如果源十六进制字符数组是一个奇怪的长度，将抛出运行时异常
     */
    public static byte[] decodeHex(char[] data) {
        int len = data.length;
        if ((len & 0x01) != 0) {
            throw new RuntimeException("Odd number of characters.");
        }
        byte[] out = new byte[len >> 1];
        // two characters form the hex value.
        for (int i = 0, j = 0; j < len; i++) {
            int f = toDigit(data[j], j) << 4;
            j++;
            f = f | toDigit(data[j], j);
            j++;
            out[i] = (byte) (f & 0xFF);
        }
        return out;
    }

    public static int decodeHex(char[] data, byte[] out, int pos) {
        int len = data.length;
        if ((len & 0x01) != 0) {
            throw new RuntimeException("Odd number of characters.");
        }
        // two characters form the hex value.
        for (int i = 0, j = 0; j < len; i++) {
            int f = toDigit(data[j], j) << 4;
            j++;
            f = f | toDigit(data[j], j);
            j++;
            out[i + pos] = (byte) (f & 0xFF);
        }
        return len;
    }

    public static int decodeHex(String value, byte[] bytes, int pos) {
        char[] chars = value.toCharArray();

        return decodeHex(chars, bytes, pos);

    }

    /**
     * 整数转成指定从长度的十六进制数
     *
     * @param value
     * @param len
     */
    public static String int2HexStr(int value, int len) {
        String result = Integer.toHexString(value);
        int i = result.length();
        if (i > len) {
            return result.substring(i - len);
        } else if (i < len) {
            // 前面补充0
            StringBuilder sb = new StringBuilder(len);
            for (int j = i; j < len; ++j) {
                sb.append('0');
            }
            sb.append(result);
            return sb.toString();
        } else {
            return result;
        }

    }

    /**
     * @param b
     * @param s
     * @param n
     * @return
     */
    public static int toInt(byte[] b, int s, int n) {
        int ret = 0;

        final int e = s + n;
        for (int i = s; i < e; ++i) {
            ret <<= 8;
            ret |= b[i] & 0xFF;
        }
        return ret;
    }

    public static String formatHex(String str) {

        int len = str.length();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < len; i += 8) {
            sb.append(str, i, Math.min(i + 8, str.length()));
            sb.append(' ');
        }

        return sb.toString();

    }

    /**
     * 二进制字符串转成byte[]
     *
     * @return
     */
    public static byte[] binStr2byteArray(String src) {
        int len = src.length() >> 3;
        byte[] result = new byte[len];
        for (int i = 0; i < len; ++i) {
            String bin = src.substring(i * 8, i * 8 + 8);
            result[i] = (byte) Integer.parseInt(bin, 2);
        }
        return result;
    }

    /**
     * @param encodeHex
     * @return
     */
    public static String hexDecimal(char[] encodeHex) {
        StringBuilder sb = new StringBuilder();
        for (char c : encodeHex) {
            sb.append(String.format("%02X", (int) c));
        }
        return sb.toString();

    }

    /**
     * 异或和
     *
     * @return
     */
    public static byte xorsum(byte[] src, int len) {
        byte result = 0;
        for (int i = 0; i < len; ++i) {
            result ^= src[i];
        }
        return result;
    }

    public static String padLeftZero(String value, int len) {
        if (value == null || value.equals("null")) {
            value = "";
        }
        int valueLen = value.length();
        if (valueLen < len) {

            StringBuilder stringBuilder = new StringBuilder();
            for (int i = valueLen; i < len; ++i) {
                stringBuilder.append("0");
            }
            stringBuilder.append(value);
            value = stringBuilder.toString();
        } else if (valueLen > len) {
            throw new RuntimeException("String " + value + " length is greater than " + len);
        }

        return value;
    }

    public static String padRightZero(String value, int len) {
        if (value == null || value.equals("null")) {
            value = "";
        }
        int valueLen = value.length();
        if (valueLen < len) {
            StringBuilder stringBuilder = new StringBuilder(value);
            for (int i = valueLen; i < len; ++i) {
                stringBuilder.append("0");
            }
            value = stringBuilder.toString();
        } else if (valueLen > len) {
            throw new RuntimeException("String " + value + " length is greater than " + len);
        }
        return value;
    }

    public static String toHexString(int n) {
        byte[] bytes = new byte[4];

        bytes[0] = (byte) (n & 0xff);
        bytes[1] = (byte) ((n >> 8) & 0xff);
        bytes[2] = (byte) ((n >> 16) & 0xff);
        bytes[3] = (byte) ((n >> 24) & 0xff);

        return HexUtils.encodeHexStr(bytes);
    }

    /**
     * 将字节数组转换为十六进制字符数组
     *
     * @param data     byte[]
     * @param toDigits 用于控制输出的char[]
     * @return 十六进制char[]
     */
    protected static char[] encodeHex(byte[] data, int l, char[] toDigits) {
        char[] out = new char[l << 1];
        // two characters form the hex value.
        for (int i = 0, j = 0; i < l; i++) {
            out[j++] = toDigits[(0xF0 & data[i]) >>> 4];
            out[j++] = toDigits[0x0F & data[i]];
        }
        return out;
    }

    protected static char[] encodeHex(byte[] data, int start, int l, char[] toDigits) {
        char[] out = new char[l << 1];
        // two characters form the hex value.
        for (int i = 0, j = 0; i < l; i++) {
            out[j++] = toDigits[(0xF0 & data[start + i]) >>> 4];
            out[j++] = toDigits[0x0F & data[start + i]];
        }
        return out;
    }

    /**
     * 将字节数组转换为十六进制字符串
     *
     * @param data     byte[]
     * @param toDigits 用于控制输出的char[]
     * @return 十六进制String
     */
    protected static String encodeHexStr(byte[] data, int len, char[] toDigits) {
        return new String(encodeHex(data, len, toDigits));
    }

    /**
     * 将十六进制字符转换成一个整数
     *
     * @param ch    十六进制char
     * @param index 十六进制字符在字符数组中的位置
     * @return 一个整数
     * @throws RuntimeException 当ch不是一个合法的十六进制字符时，抛出运行时异常
     */
    protected static int toDigit(char ch, int index) {
        int digit = Character.digit(ch, 16);
        if (digit == -1) {
            throw new RuntimeException("Illegal hexadecimal character " + ch + " at index " + index);
        }
        return digit;
    }
}
